﻿// ===============================================================================
//  Copyright © ymind.net. All rights reserved .
//  官方网站：http://ymind.net/
//  版权所有：彦铭工作室 老陈出品
// ===============================================================================

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;

namespace Lcsoft.TemplateEngine
{
	/// <summary>
	/// 表示键和值的集合
	/// </summary>
	/// <typeparam name="TKey">字典中的键的类型。</typeparam>
	/// <typeparam name="TValue">字典中的值的类型。</typeparam>
	[Serializable]
	[ComVisible(false)]
	[DebuggerDisplay("Count = {Count}")]
	public class SafeDictionary<TKey, TValue> : Dictionary<TKey, TValue>
	{
		private HashSet<TKey> _protectedKeys = new HashSet<TKey>();

		/// <summary>
		/// 初始化 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 类的新实例，该实例为空且具有默认的初始容量，并使用键类型的默认相等比较器。
		/// </summary>
		public SafeDictionary() { }

		/// <summary>
		/// 初始化 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 类的新实例，该实例包含从指定的 <see cref="System.Collections.Generic.IDictionary&lt;TKey,TValue&gt;"/> 中复制的元素并为键类型使用默认的相等比较器。
		/// </summary>
		/// <param name="dictionary"><see cref="System.Collections.Generic.IDictionary&lt;TKey,TValue&gt;"/>，它的元素被复制到新的 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 中。</param>
		public SafeDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { }

		/// <summary>
		/// 初始化 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 类的新实例，该实例为空且具有默认的初始容量，并使用指定的 <see cref="System.Collections.Generic.EqualityComparer&lt;T&gt;"/>。
		/// </summary>
		/// <param name="comparer">比较键时要使用的 <see cref="System.Collections.Generic.EqualityComparer&lt;T&gt;"/> 实现，或者为 null，以便为键类型使用默认的 <see cref="System.Collections.Generic.EqualityComparer&lt;T&gt;"/>。</param>
		public SafeDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { }

		/// <summary>
		/// 初始化 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 类的新实例，该实例为空且具有指定的初始容量，并为键类型使用默认的相等比较器。
		/// </summary>
		/// <param name="capacity"><see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 可包含的初始元素数。</param>
		public SafeDictionary(int capacity) : base(capacity) { }

		/// <summary>
		/// 初始化 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 类的新实例，该实例包含从指定的 <see cref="System.Collections.Generic.IDictionary&lt;TKey,TValue&gt;"/> 中复制的元素并使用指定的 <see cref="System.Collections.Generic.EqualityComparer&lt;T&gt;"/>。
		/// </summary>
		/// <param name="dictionary"><see cref="System.Collections.Generic.IDictionary&lt;TKey,TValue&gt;"/>，它的元素被复制到新的 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 中。</param>
		/// <param name="comparer">比较键时要使用的 <see cref="System.Collections.Generic.EqualityComparer&lt;T&gt;"/> 实现，或者为 null，以便为键类型使用默认的 <see cref="System.Collections.Generic.EqualityComparer&lt;T&gt;"/>。</param>
		public SafeDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { }

		/// <summary>
		/// 初始化 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 类的新实例，该实例为空且具有指定的初始容量，并使用指定的 <see cref="System.Collections.Generic.IEqualityComparer&lt;T&gt;"/>。
		/// </summary>
		/// <param name="capacity"><see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 可包含的初始元素数。</param>
		/// <param name="comparer">比较键时要使用的 <see cref="System.Collections.Generic.IEqualityComparer&lt;T&gt;"/> 实现，或者为 null，以便为键类型使用默认的 <see cref="System.Collections.Generic.EqualityComparer&lt;T&gt;"/>。</param>
		public SafeDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { }

		/// <summary>
		/// 用序列化数据初始化 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 类的新实例。
		/// </summary>
		/// <param name="info">一个 <see cref="System.Runtime.Serialization.SerializationInfo"/> 对象，它包含序列化 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 所需的信息。</param>
		/// <param name="context"><see cref="System.Runtime.Serialization.StreamingContext"/> 结构，该结构包含与 <see cref="SafeDictionary&lt;TKey,TValue&gt;"/> 相关联的序列化流的源和目标。</param>
		protected SafeDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }

		/// <summary>
		/// 获取或设置受保护的键，这些键的内容可以被修改，但无法删除。
		/// </summary>
		public HashSet<TKey> ProtectedKeys
		{
			get { return this._protectedKeys ?? (this._protectedKeys = new HashSet<TKey>()); }
		}

		/// <summary>
		/// 将指定的键和值添加到字典中。当指定的键存在时，会自动覆盖。
		/// </summary>
		/// <param name="key">要添加的元素的键。</param>
		/// <param name="value">要添加的元素的值。对于引用类型，该值可以为 null。</param>
		public new void Add(TKey key, TValue value)
		{
			if (this.ContainsKey(key)) this[key] = value;
			else base.Add(key, value);
		}

		/// <summary>
		/// 将指定的键和值添加到字典中。当指定的键存在时，会自动覆盖。
		/// </summary>
		/// <param name="key">要添加的元素的键。</param>
		/// <param name="value">要添加的元素的值。对于引用类型，该值可以为 null。</param>
		/// <param name="protected">指定要添加的元素的键是否为受保护的。如果设置为 true，则该键值无法直接删除（但可以更改），必须从受保护的键列表中移除该键名之后才能正常删除此键的内容。</param>
		public void Add(TKey key, TValue value, bool @protected)
		{
			this.Add(key, value);

			if (@protected && this.ProtectedKeys.Contains(key) == false) this.ProtectedKeys.Add(key);
		}

		/// <summary>
		/// 从字典中移除所指定的键的值。
		/// </summary>
		/// <param name="key">要移除的元素的键。</param>
		/// <returns>如果成功找到并移除该元素，则为 true；否则为 false。</returns>
		public new bool Remove(TKey key) { return this.ProtectedKeys.Contains(key) == false && base.Remove(key); }
	}
}
